package com.base.common.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.*;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 统一请求
 */
public class HttpClientHelper {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final CloseableHttpClient httpClient;

    public HttpClientHelper() {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(8000)
                .setConnectionRequestTimeout(3000)
                .build();

        this.httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setMaxConnTotal(100)
                .setMaxConnPerRoute(20)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
                .build();

        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /* -------------------------------------------------------------
     * 基础泛型支持：可传入任意 TypeReference<BaseResponse<T>>
     * ------------------------------------------------------------- */
    public <T> Optional<T> get(String url, TypeReference<BaseResponse<T>> typeRef) {
        return get(url, null, typeRef);
    }

    public <T> Optional<T> get(String url, Map<String, String> headers, TypeReference<BaseResponse<T>> typeRef) {
        HttpGet request = new HttpGet(url);
        request.addHeader("Accept", "application/json");
        if (headers != null) headers.forEach(request::addHeader);
        return executeRequest(request, typeRef);
    }

    public <T> Optional<T> post(String url, Object bodyObj, TypeReference<BaseResponse<T>> typeRef) {
        return post(url, bodyObj, null, typeRef);
    }

    public <T> Optional<T> post(String url, Object bodyObj, Map<String, String> headers, TypeReference<BaseResponse<T>> typeRef) {
        HttpPost request = (HttpPost) buildJsonRequest(new HttpPost(url), bodyObj, headers);
        return executeRequest(request, typeRef);
    }

    /* -------------------------------------------------------------
     * 智能推断封装（无需写 TypeReference）
     * ------------------------------------------------------------- */

    // ✅ 获取单个对象
    public <T> Optional<T> get(String url, Class<T> clazz) {
        TypeReference<BaseResponse<T>> typeRef = buildTypeReference(clazz);
        return get(url, null, typeRef);
    }

    // ✅ 获取列表对象
    public <T> Optional<List<T>> getList(String url, Class<T> elementClass) {
        TypeReference<BaseResponse<List<T>>> typeRef = buildListTypeReference(elementClass);
        return get(url, null, typeRef);
    }

    // ✅ POST 单对象
    public <T> Optional<T> post(String url, Object bodyObj, Class<T> clazz) {
        TypeReference<BaseResponse<T>> typeRef = buildTypeReference(clazz);
        return post(url, bodyObj, null, typeRef);
    }

    // ✅ POST 列表对象
    public <T> Optional<List<T>> postList(String url, Object bodyObj, Class<T> elementClass) {
        TypeReference<BaseResponse<List<T>>> typeRef = buildListTypeReference(elementClass);
        return post(url, bodyObj, null, typeRef);
    }

    /* -------------------------------------------------------------
     * 执行请求通用逻辑
     * ------------------------------------------------------------- */
    private <T> Optional<T> executeRequest(HttpUriRequest request, TypeReference<BaseResponse<T>> typeRef) {
        try (CloseableHttpResponse response = httpClient.execute(request)) {
            int status = response.getStatusLine().getStatusCode();
            String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);

            if (status == 200 || status == 201) {
                BaseResponse<T> baseResponse = objectMapper.readValue(body, typeRef);
                if (baseResponse != null && baseResponse.getCode() == 0) {
                    return Optional.ofNullable(baseResponse.getData());
                } else {
                    System.err.printf("接口返回失败：code=%d, message=%s%n",
                            baseResponse != null ? baseResponse.getCode() : -1,
                            baseResponse != null ? baseResponse.getMessage() : "解析失败");
                }
            } else {
                System.err.printf("%s 请求失败 [status=%d, url=%s, body=%s]%n",
                        request.getMethod(), status, request.getURI(), body);
            }
        } catch (IOException e) {
            System.err.printf("%s 请求异常：%s [url=%s]%n", request.getMethod(), e.getMessage(), request.getURI());
        }
        return Optional.empty();
    }

    /* -------------------------------------------------------------
     * 构建 JSON 请求体
     * ------------------------------------------------------------- */
    private HttpEntityEnclosingRequestBase buildJsonRequest(HttpEntityEnclosingRequestBase request, Object bodyObj, Map<String, String> headers) {
        request.addHeader("Content-Type", "application/json");
        request.addHeader("Accept", "application/json");
        if (headers != null) headers.forEach(request::addHeader);

        if (bodyObj != null) {
            try {
                String json = objectMapper.writeValueAsString(bodyObj);
                request.setEntity(new StringEntity(json, StandardCharsets.UTF_8));
            } catch (Exception e) {
                System.err.printf("%s 请求序列化异常：%s%n", request.getMethod(), e.getMessage());
            }
        }
        return request;
    }

    /* -------------------------------------------------------------
     * 类型辅助方法：自动生成 TypeReference
     * ------------------------------------------------------------- */
    private <T> TypeReference<BaseResponse<T>> buildTypeReference(Class<T> clazz) {
        return new TypeReference<BaseResponse<T>>() {
            @Override
            public Type getType() {
                return objectMapper.getTypeFactory()
                        .constructParametricType(BaseResponse.class, clazz);
            }
        };
    }

    private <T> TypeReference<BaseResponse<List<T>>> buildListTypeReference(Class<T> elementClass) {
        return new TypeReference<BaseResponse<List<T>>>() {
            @Override
            public Type getType() {
                return objectMapper.getTypeFactory()
                        .constructParametricType(BaseResponse.class,
                                objectMapper.getTypeFactory().constructCollectionType(List.class, elementClass));
            }
        };
    }
}
